package com.design.service.impl;

import com.design.constant.CacheConstants;
import com.design.constant.SecurityConstants;
import com.design.domain.form.LoginForm;
import com.design.domain.form.LoginUser;
import com.design.domain.result.CommonResult;
import com.design.domain.vo.SysUser;
import com.design.redis.RedisCache;
import com.design.service.ILoginService;
import com.design.service.IUserService;
import com.design.util.JwtUtil;
import com.design.util.SecurityUtils;
import com.design.util.uuid.IdUtils;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

	private static final Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);


	@Value("${token.header}")
	private String header;

	private final static long expireTime = CacheConstants.EXPIRATION;

	@Autowired
	private IUserService userService;

	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private RedisCache redisCache;

	@Override
	public CommonResult login(LoginForm loginForm) {
		UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginForm.getLoginUser(), loginForm.getLoginPswd());
		// 调用UserDetailsServeceImpl.loadUserByUsername方法
		Authentication authenticate = authenticationManager.authenticate(authenticationToken);
		if (null == authenticate) {
			throw new RuntimeException("用户名或密码错误");
		}
		LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
		return CommonResult.success(createToken(loginUser));
	}

	/**
	 * @description: 注册需要使用手机号码+密码
	 * @author yue-han
	 * @date 2024-11-05
	 */
	@Override
	public CommonResult register(LoginForm loginForm) {
		if (null == loginForm) {
			return CommonResult.error("请输入手机号码");
		}
		String userPhone = loginForm.getUserPhone();
		String loginPswd = loginForm.getLoginPswd();
		if (null == userPhone || "".equals(userPhone) || userPhone.trim().length() == 0) {
			return CommonResult.error("请输入手机号码");
		}
		if (null == loginPswd || "".equals(loginPswd) || loginPswd.trim().length() == 0) {
			return CommonResult.error("请输入密码");
		}
		// 手机号码查重
		int count = userService.getCountByUserPhone(userPhone);
		if (count > 0) {
			return CommonResult.error("该手机号码已注册");
		}
		// 密码加密
		String encryptPassword = SecurityUtils.encryptPassword(loginPswd);
		// 插入用户信息
		SysUser insertUser = new SysUser();
		insertUser.setUserPhone(userPhone);
		String uuid = IdUtils.simpleUUID();
		insertUser.setUserName(uuid);
		insertUser.setUserSex("0");
		insertUser.setUserPswd(encryptPassword);
		insertUser.setCreateUser(1L);
		int insertCount = userService.insertUser(insertUser);
		return insertCount > 0 ? CommonResult.success("注册成功") : CommonResult.error("注册失败");
	}

	@Override
	public LoginUser getLoginUser(HttpServletRequest request) {
		String url = request.getRequestURI();
		String token = getToken(request);
		if (null == token || "".equals(token)) {
			return null;
		}
		Claims claims = JwtUtil.parseToken(token);
		if (null == claims) {
			return null;
		}
		String userKey = JwtUtil.getUserKey(claims);
		String tokenKey = getTokenKey(userKey);
		boolean isLogin = redisCache.exists(tokenKey);
		if (!isLogin) {
			return null;
		}
		LoginUser loginUser = redisCache.getCacheObject(tokenKey);
		return loginUser;
	}

	// 验证令牌有效期，自动刷新缓存
	@Override
	public void verifyToken(LoginUser loginUser) {
		refreshToken(loginUser);
	}

	private String getToken(HttpServletRequest request) {
		String token = request.getHeader(header);
		return token;
	}

	// 创建token
	private HashMap<String, Object> createToken(LoginUser loginUser) {
		String token = IdUtils.fastUUID();
		SysUser user = loginUser.getSysUser();
		Long userId = user.getUserId();
		String userName = user.getUserName();
		// 设置登录用户信息
		loginUser.setUserId(userId);
		loginUser.setUserName(userName);
		loginUser.setToken(token);
		// 删除以前的token
		String cacheKey = CacheConstants.LOGIN_TOKEN_KEY + "*";
		Collection<String> keys = redisCache.keys(cacheKey);
		for (String key : keys) {
			LoginUser oldLoginUser = redisCache.getCacheObject(key);
			if (userId.equals(oldLoginUser.getUserId())) {
				redisCache.deleteObject(key);
			}
		}
		// 刷新token有效期
		refreshToken(loginUser);
		HashMap<String, Object> claimsMap = new HashMap<>();
		claimsMap.put(SecurityConstants.USER_KEY, token);
		claimsMap.put(SecurityConstants.DETAILS_USER_ID, userId);
		claimsMap.put(SecurityConstants.DETAILS_USER_NAME, userName);

		// 接口返回信息
		HashMap<String, Object> rspMap = new HashMap<String, Object>();
		rspMap.put("access_token", JwtUtil.createToken(claimsMap));
		rspMap.put("expires_in", expireTime);
		return rspMap;
	}

	// 刷新token
	private void refreshToken(LoginUser loginUser) {
		long currented = System.currentTimeMillis();
		loginUser.setLoginTime(currented);
		loginUser.setExpireTime(currented + expireTime * 1000);
		String userKey = getTokenKey(loginUser.getToken());
		logger.info("刷新token:【{}】,{}_{}", loginUser.getToken(), expireTime, TimeUnit.MINUTES);
		// 60分钟失效
		redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
	}

	private String getTokenKey(String token) {
		return CacheConstants.LOGIN_TOKEN_KEY + token;
	}
}
